/** by Emanuil Rusev | FXComponents.com */

package com.fxcomponents
{
	import com.fxcomponents.events.FXSoundEvent;
	import com.fxcomponents.mp3player.PlayButton;
	import com.fxcomponents.mp3player.StopButton;
	import com.fxcomponents.mp3player.TimerTF;
	
	import flash.display.Shape;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.MouseEvent;
	import flash.events.ProgressEvent;
	import flash.net.URLRequest;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFormat;
	
	import mx.core.UIComponent;
	
	[Event(name="ioError", type="flash.events.IOErrorEvent")]
	
	public class MP3Player extends UIComponent
	{
		public function MP3Player()
		{
			format = new TextFormat();
			format.font = "Verdana";
			format.size = 9;
			
			super();
		}
		
		// Variables
		
		private var progress1:Number = 0;
		private var progress2:Number = 0;
		
		private var border:Shape;
		private var progressBar1:Shape;
		private var progressBar2:Shape;
		
		private var titleTF:TextField;
		private var timerTF:TimerTF;
		
		private var format:TextFormat;
		
		private var playButton:PlayButton;
		private var stopButton:StopButton;
		
		private var fxSound:FXSound;
		
		// Properties
		
		private var _trackURL:String = "";
		private var trackURLChanged:Boolean;
		
		public function set trackURL(value:String):void
		{
			_trackURL = value;
			trackURLChanged = true;
			
			invalidateProperties();
		}
		
		private var _title:String = "";
		private var titleChanged:Boolean = true;
		
		public function set title(value:String):void
		{
			_title = value;
			titleChanged = true;
			
			invalidateProperties();
		}
		
		private var _volume:uint = 80;
		private var volumeChanged:Boolean = true;
		
		public function set volume(value:uint):void
		{
			_volume = value;
			volumeChanged = true;
			
			invalidateProperties();
		}
		
		private var _timerMode:uint;
		private var timerModeChanged:Boolean = true;
		
		public function set timerMode(value:uint):void
		{
			_timerMode = value;
			timerModeChanged = true;
			
			invalidateProperties();
		}
		
		private var _autoPlay:Boolean;
		private var autoPlayChanged:Boolean;
		
		public function get autoPlay():Boolean
		{
			return _autoPlay;
		}
		
		public function set autoPlay(value:Boolean):void
		{
			_autoPlay = value;
			autoPlayChanged = true;
		
			invalidateProperties();
		}
		
		/** 
		 * color1 - background;
		 * color2 - progress bars in the background;
		 * color3 - text and buttons;
		 * color4 - buttons on roll over;
		 */
		
		private var _color1:uint = 0x333333;
		private var color1Changed:Boolean = true;
		
		public function set color1(value:uint):void
		{
			_color1 = value;
			color1Changed = true;
			
			invalidateDisplayList();
		}
		
		private var _color2:uint = 0x444444;
		private var color2Changed:Boolean = true;
		
		public function set color2(value:uint):void
		{
			_color2 = value;
			
			invalidateDisplayList();
		}
		
		private var _color3:uint = 0xdddddd;
		private var color3Changed:Boolean = true;
		
		public function set color3(value:uint):void
		{
			_color3 = value;
			color3Changed = true;
			
			invalidateProperties();
			invalidateDisplayList();
		}
		
		private var _color4:uint = 0xffffff;
		private var color4Changed:Boolean = true;
		
		public function set color4(value:uint):void
		{
			_color4 = value;
			color4Changed = true;
			
			invalidateProperties();
		}
		
		private var _cornerRadius:uint = 3;
		private var cornerRadiusChanged:Boolean = true;
		
		public function set cornerRadius(value:uint):void
		{
			_cornerRadius = value;
			cornerRadiusChanged = true;
			
			invalidateDisplayList();
		}
		
		private var _buttonWidth:uint = 20;
		private var buttonWidthChanged:Boolean = true;
		
		public function set buttonWidth(value:uint):void
		{
			_buttonWidth = value;
			buttonWidthChanged = true;
			
			invalidateDisplayList();
		}
		
		// Overridden methods: UIComponent
		
		override protected function createChildren():void
		{
			super.createChildren();
			
			border = new Shape();
			addChild(border)
			
			progressBar1 = new Shape();
			addChild(progressBar1);
			
			progressBar2 = new Shape();
			addChild(progressBar2);
			
			playButton = new PlayButton();
			playButton.iconShape = PlayButton.PLAY;
			playButton.addEventListener(MouseEvent.CLICK, play_onClick);
			addChild(playButton);
			
			stopButton = new StopButton();
			stopButton.addEventListener(MouseEvent.CLICK, stop_onClick);
			addChild(stopButton);
			
			titleTF = new TextField();
			titleTF.alpha = .8
			titleTF.defaultTextFormat = format;
			titleTF.autoSize = TextFieldAutoSize.LEFT;
			titleTF.selectable = false;
			addChild(titleTF);
			
			timerTF = new TimerTF();
			timerTF.alpha = .8;
			timerTF.defaultTextFormat = format;
			timerTF.time = 0;
			addChild(timerTF);
			
			mask = border;
		}
		
		override protected function commitProperties():void
		{
			super.commitProperties();
			
			if(_trackURL && trackURLChanged)
			{
				if(fxSound && fxSound.isPlaying)
				{
					fxSound.stop();
					playButton.iconShape = PlayButton.PLAY;
					progress1 = 0;
					invalidateDisplayList();
				}
				
				// Seems like a new Sound object is requred for each Sound.load().
				
				fxSound = new FXSound();
				
				fxSound.addEventListener(FXSoundEvent.PLAYHEAD_UPDATE, onPlayheadUpdate);
				fxSound.addEventListener(FXSoundEvent.COMPLETE, onComplete);
				fxSound.addEventListener(ProgressEvent.PROGRESS, onProgress);
				fxSound.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
				fxSound.addEventListener(Event.OPEN, onOpen);
				
				fxSound.load(new URLRequest(_trackURL));
				
				trackURLChanged = false;
			}
			
			if(color3Changed)
			{
				playButton.color = _color3;
				stopButton.color = _color3;
				
				format.color = _color3;
				format.color = _color3;
				
				titleTF.setTextFormat(format);
				timerTF.setTextFormat(format);
				
				titleTF.defaultTextFormat = format;
				timerTF.defaultTextFormat = format;
				
				color3Changed = false;
			}
			
			if(color4Changed)
			{
				playButton.rollOverColor = _color4;
				stopButton.rollOverColor = _color4;
				
				color4Changed = false;
			}
			
			if(titleChanged)
			{
				titleTF.text = _title;
				titleChanged = false;
			}
			
			if(timerModeChanged)
			{
				timerTF.mode = _timerMode;
				timerModeChanged = false;
			}
			
			if(volumeChanged && fxSound)
			{
				fxSound.volume = _volume;
				volumeChanged = false;
			}
			
			if(autoPlayChanged)
			{
				
			}
		}
		
		override protected function measure():void
		{
			super.measure();
			
			measuredWidth = 300;
			measuredHeight = 20;
		}
		
		override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
		{
			super.updateDisplayList(unscaledWidth, unscaledHeight);
			
			graphics.clear();
			graphics.beginFill(_color1);
			graphics.drawRect(0, 0, unscaledWidth, unscaledHeight);
			
			border.graphics.clear();
			border.graphics.beginFill(0);
			border.graphics.drawRoundRectComplex(0, 0, unscaledWidth, unscaledHeight, _cornerRadius, _cornerRadius, _cornerRadius, _cornerRadius);
			
			progressBar1.graphics.clear();
			progressBar1.graphics.beginFill(_color2);
			progressBar1.graphics.drawRect(0, 0, uint(unscaledWidth*progress1), 10)
			
			progressBar2.graphics.clear();
			progressBar2.graphics.beginFill(_color2);
			progressBar2.graphics.drawRect(0, 10, uint(unscaledWidth*progress2), 10)
			
			if(buttonWidthChanged)
			{
				playButton.move(0, 0);
				playButton.setActualSize(_buttonWidth, 20);
				
				stopButton.move(playButton.width, 0);
				stopButton.setActualSize(_buttonWidth, 20);
				
				titleTF.x = stopButton.x + stopButton.width + 5;
				titleTF.y = 1;
				
				timerTF.x = unscaledWidth - timerTF.width - 5;
				timerTF.y = 1;
			}
		}
		
		// Event Handlers
		
		private function onProgress(e:ProgressEvent):void
		{
			progress2 = e.bytesLoaded/e.bytesTotal;
			
			timerTF.total = fxSound.estimatedLength/1000;
			
			invalidateDisplayList();
		}
		
		private function play_onClick(e:MouseEvent):void
		{
			if(!fxSound)
				return;
			
			if(!fxSound.isPlaying)
			{
				if(fxSound.resume())
					playButton.iconShape = PlayButton.PAUSE;
				
				return;
			}
			
			if(fxSound.isPlaying)
			{
				fxSound.pause();
				playButton.iconShape = PlayButton.PLAY;
				return;
			}
		}
		
		private function stop_onClick(e:MouseEvent):void
		{
			if(!fxSound)
				return;
			
			fxSound.stop();
			playButton.iconShape = PlayButton.PLAY;
			progress1 = 0;
			timerTF.time = 0;
			invalidateDisplayList();
		}
		
		private function onPlayheadUpdate(e:FXSoundEvent):void
		{
			timerTF.time = e.playheadTime/1000;
			
			progress1 = e.playheadTime/e.target.estimatedLength;
			invalidateDisplayList();
		}
		
		private function onComplete(e:FXSoundEvent):void
		{
			stop_onClick(new MouseEvent(MouseEvent.CLICK));
		}
		
		private function onIOError(e:IOErrorEvent):void
		{
			dispatchEvent(e.clone());
		}
		
		private function onOpen(e:Event):void
		{
			if(autoPlay)
			{
				fxSound.resume();
				playButton.iconShape = PlayButton.PAUSE;
			}
		}
	}
}